package com.fs.sw.common.jpa.repository;

import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
		implements BaseRepository<T, ID> {

	private final EntityManager entityManager;

//	public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
//		super(domainClass, entityManager);
//		this.entityManager = entityManager;
//	}

	public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
		super(entityInformation, entityManager);
		this.entityManager = entityManager;
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryIdxParm(String namedQuery, Map<Integer, Object> params) {
		return executeQuery(true, namedQuery, (Map<T, Object>) params, -1, 0);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryNameParm(String namedQuery, Map<String, Object> params) {
		return executeQuery(true, namedQuery, (Map<T, Object>) params, -1, 0);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryIdxParm(String namedQuery, Map<Integer, Object> params, int pageNum, int pageSize) {
		return executeQuery(true, namedQuery, (Map<T, Object>) params, pageNum, pageSize);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryNameParm(String namedQuery, Map<String, Object> params, int pageNum, int pageSize) {
		return executeQuery(true, namedQuery, (Map<T, Object>) params, pageNum, pageSize);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryCustIdxParm(String jpql, Map<Integer, Object> params) {
		return executeQuery(false, jpql, (Map<T, Object>) params, -1, 0);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryCustNameParm(String jpql, Map<String, Object> params) {
		return executeQuery(false, jpql, (Map<T, Object>) params, -1, 0);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryCustIdxParm(String jpql, Map<Integer, Object> params, int pageNum, int pageSize) {
		return executeQuery(false, jpql, (Map<T, Object>) params, pageNum, pageSize);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeQueryCustNameParm(String jpql, Map<String, Object> params, int pageNum, int pageSize) {
		return executeQuery(false, jpql, (Map<T, Object>) params, pageNum, pageSize);
	}

	public Object getSingleResultNqI(String namedQuery, Map<Integer, Object> params) {
		return null;
	}

	public Object getSingleResultNqS(String namedQuery, Map<String, Object> params) {
		return null;
	}

	public Object getSingleResultJpqlI(String jpql, Map<Integer, Object> params) {
		return null;
	}

	public Object getSingleResultJpqlS(String jpql, Map<String, Object> params) {
		return null;
	}

	private List<T> executeQuery(boolean isNamedQuery, String jpQuery, Map<T, Object> params, int pageNum,
			int pageSize) {
		Query query = null;
		if (isNamedQuery) {
			query = entityManager.createNamedQuery(jpQuery);
		} else {
			query = entityManager.createQuery(jpQuery);
		}
		return executeQuery(query, (Map<T, Object>) params, pageNum, pageSize);
	}

	@SuppressWarnings("unchecked")
	private List<T> executeQuery(Query query, Map<T, Object> params, int pageNum, int pageSize) {
		if (params != null) {
			String strParam = "";
			for (Entry<T, Object> entry : params.entrySet()) {
				strParam = String.valueOf(entry.getKey());
				if (entry.getKey().getClass() == String.class) {
					query.setParameter(strParam, entry.getValue());
				} else {
					query.setParameter(Integer.valueOf(strParam), entry.getValue());
				}
			}
		}
		if (pageNum > 0) {
			query.setFirstResult((pageNum - 1) * pageSize).setMaxResults(pageSize);
		}

		return query.getResultList();
	}

	// @SuppressWarnings("unchecked")
	// private List<T> executeQueryIntMap(boolean isNamedQuery, String jpQuery,
	// Map<Integer, Object> params, int pageNum,
	// int pageSize) {
	// Query query = null;
	// if (isNamedQuery) {
	// query = entityManager.createNamedQuery(jpQuery);
	// } else {
	// query = entityManager.createQuery(jpQuery);
	// }
	// if (params != null) {
	// for (Map.Entry<Integer, Object> entry : params.entrySet()) {
	// query.setParameter(entry.getKey(), entry.getValue());
	// }
	// }
	// if (pageNum > 0) {
	// query.setFirstResult((pageNum - 1) * pageSize);
	// query.setMaxResults(pageSize);
	// }
	//
	// return query.getResultList();
	// }
	//
	// @SuppressWarnings("unchecked")
	// private List<T> executeQueryStrMap(boolean isNamedQuery, String jpQuery,
	// Map<String, Object> params, int pageNum,
	// int pageSize) {
	// Query query = null;
	// if (isNamedQuery) {
	// query = entityManager.createNamedQuery(jpQuery);
	// } else {
	// query = entityManager.createQuery(jpQuery);
	// }
	// if (params != null) {
	// for (Map.Entry<String, Object> entry : params.entrySet()) {
	// query.setParameter(entry.getKey(), entry.getValue());
	// }
	// }
	// if (pageNum > 0) {
	// query.setFirstResult((pageNum - 1) * pageSize);
	// query.setMaxResults(pageSize);
	// }
	//
	// return query.getResultList();
	// }

	// @SuppressWarnings("unchecked")
	// private List<T> executeQueryGetSingleResult(boolean isNamedQuery, String
	// jpQuery, Map<String, Object> params,
	// int pageNum, int pageSize) {
	//
	// return null;
	// }
	
	
	// for 药品组 2019-03-08
	@SuppressWarnings("unchecked")
	public List<T> exeNativeQueryIdxParm(String jpql, Map<Integer, Object> params) {
		return executeNativeQuery(true, jpql, (Map<T, Object>) params, -1, 0);
	}
	
	private List<T> executeNativeQuery(boolean isNamedQuery, String jpql, Map<T, Object> params, int pageNum,
			int pageSize) {
		Query query = entityManager.createNativeQuery(jpql);
		return executeQuery(query, (Map<T, Object>) params, pageNum, pageSize);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeNativeQueryParm(String jpql, Map<String, Object> params) {
		return executeNativeQuery(true, jpql, (Map<T, Object>) params, -1, 0);
	}

	@SuppressWarnings("unchecked")
	public List<T> exeNativeQueryParm(String jpql, Map<String, Object> params, int pageNum, int pageSize) {
		return executeNativeQuery(true, jpql, (Map<T, Object>) params, pageNum, pageSize);
	}

	public void execBatchInsert(List<T> list, int batchSize) {
		if (batchSize <= 0) {
			batchSize = 1000;
		}

		if (list.size() > batchSize) {
			int subCount = list.size();
			int subPageTotal = (subCount / batchSize) + ((subCount % batchSize > 0) ? 1 : 0);
			int len = subPageTotal - 1;
			// 根据页码取数据
			for (int k = 0; k <= len; k++) {
				// 分页计算
				int fromIndex = k * batchSize;
				int toIndex = ((k == len) ? subCount : ((k + 1) * batchSize));
				List<T> tempList = list.subList(fromIndex, toIndex);
				for (int i = 0; i < tempList.size(); i++) {
					entityManager.persist(tempList.get(i));
				}
				entityManager.flush();
				entityManager.clear();
			}
		} else {
			for (int i = 0; i < list.size(); i++) {
				entityManager.persist(list.get(i));
			}
			entityManager.flush();
			entityManager.clear();
		}
	}

	@Override
	public T findOneWithGraph(Class<T> domainClass,ID id, String graphName) {
		EntityGraph entityGraph = entityManager.getEntityGraph(graphName);
		Map<String, Object> properties = new HashMap<>();
		properties.put("javax.persistence.fetchgraph", entityGraph);
		T customer = entityManager.find(domainClass, id, properties);
		return customer;
	}

}
